"""
API Dependencies
API依赖注入 - 数据库会话、当前用户、权限验证
"""

import uuid
from typing import Optional, List, Dict, Any
from datetime import datetime

from fastapi import Depends, HTTPException, status, Query, Path
from fastapi.security import OAuth2PasswordBearer
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, and_, or_

from ..core.database import get_db
from ..core.config import settings
from ..core.exceptions import (
    AuthenticationError,
    PermissionDeniedError,
    UserNotFoundError,
    ContentNotFoundError,
    FolderNotFoundError,
    TagNotFoundError,
    ValidationError,
)
from ..models.user import User
from ..models.generated_content import GeneratedContent
from ..models.folder import Folder
from ..models.content_tag import ContentTag
from ..core.logging import error_logger

# OAuth2方案
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/login")


async def get_current_user_from_token(
    token: str = Depends(oauth2_scheme),
    db: AsyncSession = Depends(get_db)
) -> User:
    """
    从JWT令牌获取当前用户
    
    Args:
        token: JWT访问令牌
        db: 数据库会话
        
    Returns:
        User: 当前用户对象
        
    Raises:
        AuthenticationError: 认证失败时抛出
    """
    from datetime import datetime, timedelta
    from jose import JWTError, jwt
    from ..core.config import settings
    
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="无法验证凭据",
        headers={"WWW-Authenticate": "Bearer"},
    )
    
    try:
        # 解码JWT令牌
        payload = jwt.decode(
            token,
            settings.security.secret_key,
            algorithms=[settings.security.jwt_algorithm],
        )
        user_id: str = payload.get("sub")
        if user_id is None:
            raise credentials_exception
            
        # 验证令牌过期时间
        exp = payload.get("exp")
        if exp and datetime.utcnow() > datetime.fromtimestamp(exp):
            raise credentials_exception
            
    except JWTError:
        raise credentials_exception
    
    # 查询用户
    result = await db.execute(select(User).where(User.id == uuid.UUID(user_id)))
    user = result.scalar_one_or_none()
    
    if user is None:
        raise credentials_exception
    
    # 检查用户状态
    if user.status != "active":
        raise HTTPException(
            status_code=status.HTTP_423_LOCKED,
            detail="账户已被锁定"
        )
    
    return user


def get_current_active_user(
    current_user: User = Depends(get_current_user_from_token)
) -> User:
    """
    获取当前激活用户
    
    Args:
        current_user: 当前用户
        
    Returns:
        User: 激活的用户对象
        
    Raises:
        HTTPException: 用户未激活时抛出
    """
    if not current_user.is_active:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="用户未激活"
        )
    return current_user


def get_current_admin_user(
    current_user: User = Depends(get_current_user_from_token)
) -> User:
    """
    获取当前管理员用户
    
    Args:
        current_user: 当前用户
        
    Returns:
        User: 管理员用户对象
        
    Raises:
        HTTPException: 用户不是管理员时抛出
    """
    if not current_user.is_admin:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="需要管理员权限"
        )
    return current_user


async def get_user_or_404(
    user_id: uuid.UUID,
    db: AsyncSession = Depends(get_db)
) -> User:
    """
    获取用户或返回404错误
    
    Args:
        user_id: 用户ID
        db: 数据库会话
        
    Returns:
        User: 用户对象
        
    Raises:
        HTTPException: 用户不存在时抛出404错误
    """
    result = await db.execute(select(User).where(User.id == user_id))
    user = result.scalar_one_or_none()
    
    if not user:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="用户不存在"
        )
    
    return user


async def get_content_or_404(
    content_id: uuid.UUID,
    current_user: User = Depends(get_current_user_from_token),
    db: AsyncSession = Depends(get_db)
) -> GeneratedContent:
    """
    获取内容或返回404错误，并验证权限
    
    Args:
        content_id: 内容ID
        current_user: 当前用户
        db: 数据库会话
        
    Returns:
        GeneratedContent: 内容对象
        
    Raises:
        HTTPException: 内容不存在或无权限时抛出404错误
    """
    result = await db.execute(
        select(GeneratedContent).where(
            and_(
                GeneratedContent.id == content_id,
                GeneratedContent.user_id == current_user.id,
                GeneratedContent.is_deleted == False
            )
        )
    )
    content = result.scalar_one_or_none()
    
    if not content:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="内容不存在或无权限访问"
        )
    
    return content


async def get_folder_or_404(
    folder_id: uuid.UUID,
    current_user: User = Depends(get_current_user_from_token),
    db: AsyncSession = Depends(get_db)
) -> Folder:
    """
    获取文件夹或返回404错误，并验证权限
    
    Args:
        folder_id: 文件夹ID
        current_user: 当前用户
        db: 数据库会话
        
    Returns:
        Folder: 文件夹对象
        
    Raises:
        HTTPException: 文件夹不存在或无权限时抛出404错误
    """
    result = await db.execute(
        select(Folder).where(
            and_(
                Folder.id == folder_id,
                Folder.user_id == current_user.id,
                Folder.is_deleted == False
            )
        )
    )
    folder = result.scalar_one_or_none()
    
    if not folder:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="文件夹不存在或无权限访问"
        )
    
    return folder


async def get_tag_or_404(
    tag_id: uuid.UUID,
    current_user: User = Depends(get_current_user_from_token),
    db: AsyncSession = Depends(get_db)
) -> ContentTag:
    """
    获取标签或返回404错误，并验证权限
    
    Args:
        tag_id: 标签ID
        current_user: 当前用户
        db: 数据库会话
        
    Returns:
        ContentTag: 标签对象
        
    Raises:
        HTTPException: 标签不存在或无权限时抛出404错误
    """
    result = await db.execute(
        select(ContentTag).where(
            and_(
                ContentTag.id == tag_id,
                or_(
                    ContentTag.visibility == "public",
                    ContentTag.visibility == "system",
                    ContentTag.is_system == True
                )
            )
        )
    )
    tag = result.scalar_one_or_none()
    
    if not tag:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="标签不存在"
        )
    
    return tag


def validate_content_type(content_type: str) -> str:
    """
    验证内容类型
    
    Args:
        content_type: 内容类型
        
    Returns:
        str: 验证通过的内容类型
        
    Raises:
        ValidationError: 内容类型无效时抛出
    """
    valid_types = ["image", "video", "audio", "text"]
    if content_type not in valid_types:
        raise ValidationError(
            f"无效的内容类型: {content_type}. 有效类型: {', '.join(valid_types)}"
        )
    return content_type


def validate_ai_provider(provider: str) -> str:
    """
    验证AI提供商
    
    Args:
        provider: AI提供商
        
    Returns:
        str: 验证通过的提供商
        
    Raises:
        ValidationError: 提供商无效时抛出
    """
    valid_providers = ["doubao", "ali", "openai"]
    if provider not in valid_providers:
        raise ValidationError(
            f"无效的AI提供商: {provider}. 有效提供商: {', '.join(valid_providers)}"
        )
    return provider


def validate_pagination_params(
    page: int = Query(1, ge=1, description="页码"),
    page_size: int = Query(20, ge=1, le=100, description="每页数量")
) -> Dict[str, int]:
    """
    验证分页参数
    
    Args:
        page: 页码
        page_size: 每页数量
        
    Returns:
        Dict[str, int]: 验证通过的分页参数
    """
    return {"page": page, "page_size": page_size}


def validate_sort_params(
    sort_by: Optional[str] = Query(None, description="排序字段"),
    sort_order: Optional[str] = Query("desc", description="排序方向: asc, desc")
) -> Dict[str, Optional[str]]:
    """
    验证排序参数
    
    Args:
        sort_by: 排序字段
        sort_order: 排序方向
        
    Returns:
        Dict[str, Optional[str]]: 验证通过的排序参数
    """
    valid_orders = ["asc", "desc"]
    if sort_order not in valid_orders:
        sort_order = "desc"
    
    return {"sort_by": sort_by, "sort_order": sort_order}


def validate_date_range(
    start_date: Optional[str] = Query(None, description="开始日期 (YYYY-MM-DD)"),
    end_date: Optional[str] = Query(None, description="结束日期 (YYYY-MM-DD)")
) -> Dict[str, Optional[datetime]]:
    """
    验证日期范围参数
    
    Args:
        start_date: 开始日期
        end_date: 结束日期
        
    Returns:
        Dict[str, Optional[datetime]]: 验证通过的日期范围
        
    Raises:
        ValidationError: 日期格式无效时抛出
    """
    start_datetime = None
    end_datetime = None
    
    if start_date:
        try:
            start_datetime = datetime.strptime(start_date, "%Y-%m-%d")
        except ValueError:
            raise ValidationError("无效的开始日期格式，应为 YYYY-MM-DD")
    
    if end_date:
        try:
            end_datetime = datetime.strptime(end_date, "%Y-%m-%d")
            # 结束日期应包含整天，所以加1天
            end_datetime = end_datetime + timedelta(days=1)
        except ValueError:
            raise ValidationError("无效的结束日期格式，应为 YYYY-MM-DD")
    
    # 验证日期范围
    if start_datetime and end_datetime and start_datetime >= end_datetime:
        raise ValidationError("开始日期必须早于结束日期")
    
    return {"start_date": start_datetime, "end_date": end_datetime}


class PermissionChecker:
    """权限检查器"""
    
    def __init__(self, required_permissions: List[str]):
        self.required_permissions = required_permissions
    
    def __call__(self, current_user: User = Depends(get_current_user_from_token)) -> User:
        """
        检查用户权限
        
        Args:
            current_user: 当前用户
            
        Returns:
            User: 有权限的用户对象
            
        Raises:
            PermissionDeniedError: 权限不足时抛出
        """
        # 管理员拥有所有权限
        if current_user.is_admin:
            return current_user
        
        # 检查具体权限
        user_permissions = getattr(current_user, 'permissions', [])
        
        for permission in self.required_permissions:
            if permission not in user_permissions:
                raise PermissionDeniedError(
                    f"权限不足，需要权限: {permission}"
                )
        
        return current_user


# 常用依赖组合
def get_pagination_deps():
    """获取分页依赖"""
    return Depends(validate_pagination_params)


def get_sort_deps():
    """获取排序依赖"""
    return Depends(validate_sort_params)


def get_date_range_deps():
    """获取日期范围依赖"""
    return Depends(validate_date_range)


# 内容管理相关依赖
async def get_content_filters(
    content_type: Optional[str] = Query(None, description="内容类型"),
    status: Optional[str] = Query(None, description="状态"),
    folder_id: Optional[str] = Query(None, description="文件夹ID"),
    is_favorite: Optional[bool] = Query(None, description="是否收藏"),
    search: Optional[str] = Query(None, description="搜索关键词")
) -> Dict[str, Any]:
    """
    获取内容筛选条件
    
    Args:
        content_type: 内容类型
        status: 状态
        folder_id: 文件夹ID
        is_favorite: 是否收藏
        search: 搜索关键词
        
    Returns:
        Dict[str, Any]: 筛选条件字典
    """
    filters = {}
    
    if content_type:
        filters["content_type"] = validate_content_type(content_type)
    if status:
        filters["status"] = status
    if folder_id:
        try:
            filters["folder_id"] = uuid.UUID(folder_id)
        except ValueError:
            raise ValidationError("无效的文件夹ID格式")
    if is_favorite is not None:
        filters["is_favorite"] = is_favorite
    if search:
        filters["search"] = search
    
    return filters


# 文件夹管理相关依赖
async def get_folder_validation(
    name: str = Query(..., description="文件夹名称"),
    parent_id: Optional[str] = Query(None, description="父文件夹ID")
) -> Dict[str, Any]:
    """
    验证文件夹参数
    
    Args:
        name: 文件夹名称
        parent_id: 父文件夹ID
        
    Returns:
        Dict[str, Any]: 验证通过的参数
        
    Raises:
        ValidationError: 参数无效时抛出
    """
    if not name or len(name.strip()) == 0:
        raise ValidationError("文件夹名称不能为空")
    
    # 检查非法字符
    invalid_chars = ['/', '\\', ':', '*', '?', '"', '<', '>', '|']
    if any(char in name for char in invalid_chars):
        raise ValidationError("文件夹名称包含非法字符")
    
    # 检查长度
    if len(name) > 100:
        raise ValidationError("文件夹名称过长（最大100字符）")
    
    result = {"name": name.strip()}
    
    if parent_id:
        try:
            result["parent_id"] = uuid.UUID(parent_id)
        except ValueError:
            raise ValidationError("无效的父文件夹ID格式")
    
    return result


# 标签管理相关依赖
async def get_tag_validation(
    name: str = Query(..., description="标签名称"),
    category: str = Query("custom", description="标签分类")
) -> Dict[str, Any]:
    """
    验证标签参数
    
    Args:
        name: 标签名称
        category: 标签分类
        
    Returns:
        Dict[str, Any]: 验证通过的参数
        
    Raises:
        ValidationError: 参数无效时抛出
    """
    if not name or len(name.strip()) == 0:
        raise ValidationError("标签名称不能为空")
    
    # 检查长度
    if len(name) > 50:
        raise ValidationError("标签名称过长（最大50字符）")
    
    valid_categories = [
        "content_type", "style", "subject", "color", "emotion", 
        "technique", "scene", "custom", "ai_generated"
    ]
    if category not in valid_categories:
        raise ValidationError(f"无效的标签分类: {category}")
    
    return {"name": name.strip(), "category": category}


# 系统管理相关依赖
def require_system_permission(permission: str):
    """
    要求系统权限
    
    Args:
        permission: 需要的权限
        
    Returns:
        Dependency: 权限检查依赖
    """
    return PermissionChecker([permission])


# 导出所有依赖
__all__ = [
    # 用户相关
    "get_current_user_from_token",
    "get_current_active_user", 
    "get_current_admin_user",
    "get_user_or_404",
    
    # 内容相关
    "get_content_or_404",
    "get_content_filters",
    "validate_content_type",
    
    # 文件夹相关
    "get_folder_or_404",
    "get_folder_validation",
    
    # 标签相关
    "get_tag_or_404",
    "get_tag_validation",
    
    # AI相关
    "validate_ai_provider",
    
    # 通用验证
    "validate_pagination_params",
    "validate_sort_params", 
    "validate_date_range",
    "get_pagination_deps",
    "get_sort_deps",
    "get_date_range_deps",
    
    # 权限相关
    "PermissionChecker",
    "require_system_permission",
    
    # OAuth2方案
    "oauth2_scheme"
]